import sys
import socket
import threading
from typing import List

from PyQt5.QtCore import pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import (
    QApplication,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
    QLineEdit,
    QTextEdit,
)


class ServerThread(threading.Thread):
    signal_action = pyqtSignal()
    signal_send_data = pyqtSignal()
    signal_receive_data = pyqtSignal()

    def __init__(self, host, port):
        super().__init__()
        self.client_socket = None
        self.host = host
        self.port = port
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen(1)

    def run(self):
        """
        重写run方法
        @return:
        """
        while True:
            self.client_socket, address = self.server_socket.accept()
            data = self.client_socket.recv(1024)
            self.text_output.append("Received: " + data.decode())

    def send_data(self, data):
        """
        给发送数据按钮绑定的槽函数
        @param data:
        @return:
        """
        __data = self.client_socket.sendall(data.encode())
        if __data:
            self.signal_send_data.emit(__data)

    def receive_data(self):
        """
        给接收数据按钮绑定的槽函数
        @return:
        """
        __data = self.client_socket.recv(1024)
        if __data:
            self.signal_receive_data.emit(__data)

    def action(self):
        """
        给动作按钮绑定的槽函数
        @return:
        """
        self.client_socket.close()
        self.server_socket.close()
        self.signal_action.emit()


class ClientThread(threading.Thread):
    def __init__(self, host, port: int, message):
        super().__init__()
        self.port = port
        self.message = message
        self.host = host

    def run(self):
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client_socket.connect((self.host, self.port))
        client_socket.sendall(self.message.encode())
        data = client_socket.recv(1024)
        self.text_output.append("Received: " + data.decode())
        client_socket.close()


class ServerWindow(QWidget):
    def __init__(self, port):
        super().__init__()

        self.setWindowTitle("服务器窗口")

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.text_output = QTextEdit(self)
        self.layout.addWidget(self.text_output)

        self.start_server_button = QPushButton("启动服务器", self)
        self.start_server_button.clicked.connect(self.start_server)
        self.layout.addWidget(self.start_server_button)

        self.server_thread = ServerThread(port)

    def start_server(self):
        self.server_thread.start()


class ClientWindow(QWidget):
    def __init__(self, port):
        super().__init__()

        self.port = port

        self.setWindowTitle("客户端窗口")

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.client_host = QLineEdit(self)
        self.client_port = QLineEdit(self)
        self.layout.addWidget(self.client_host)
        self.layout.addWidget(self.client_port)

        self.text_output = QTextEdit(self)
        self.layout.addWidget(self.text_output)

        self.start_client_button = QPushButton("启动客户端", self)
        self.start_client_button.clicked.connect(self.start_client)
        self.layout.addWidget(self.start_client_button)

        self.client_thread = None

    def start_client(self):
        message = self.text_output.text()
        self.client_thread = ClientThread(
            self.client_host.text(), int(self.client_port.text()), message
        )
        self.client_thread.text_output = self.text_output
        self.client_thread.start()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.server_window: List[ServerWindow] = None
        self.client_window: List[ClientWindow] = None
        self.setWindowTitle("主窗口")

        self.layout = QVBoxLayout()
        self.central_widget = QWidget(self)
        self.central_widget.setLayout(self.layout)
        self.setCentralWidget(self.central_widget)

        self.add_server_button = QPushButton("添加服务器", self)
        self.add_server_button.clicked.connect(self.add_server)
        self.layout.addWidget(self.add_server_button)

        self.add_client_button = QPushButton("添加客户端", self)
        self.add_client_button.clicked.connect(self.add_client)
        self.layout.addWidget(self.add_client_button)

        self.server_windows = []
        self.client_windows = []

    @pyqtSlot()
    def add_server(self):
        server_port = len(self.server_windows) + 8000
        self.server_window = ServerWindow(server_port)
        self.server_window.show()
        self.server_windows.append(self.server_window)

    @pyqtSlot()
    def add_client(self):
        client_port = len(self.client_windows) + 9000
        self.client_window = ClientWindow(client_port)
        self.client_window.show()
        self.client_windows.append(self.client_window)

    def closeEvent(self, event) -> None:
        """

        @param event:
        @return:
        """
        for client in self.client_windows:
            client.close()
        for server in self.server_windows:
            server.close()
        event.accept()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
